<template>
  <div class="customize-container" :style="{
    height: height
  }"
  >
    <div  class="customize-table-container"  style="height: calc(100% - 50px);">
      <table ref="customizeTable" class="customize-table"  :width="width" >
        <thead >
        <th v-if="showCheckBox" class="customize-table-checkbox-th"
            :class="{
              'customize-table-head-sticky': headFixed,
              'customize-table-col-sticky-left': fixedCheckbox
            }"
            :style="{
                zIndex: (headFixed && fixedCheckbox) ? 3 : 1
            }"
        >
          <input  :checked="allCheckboxChange" @change.stop="handleAllChange" type="checkbox"/>
        </th>
        <th class="customize-table-checkbox-th"
            :class="{
                'customize-table-head-sticky': headFixed,
                'customize-table-col-sticky-left': fixedLineNumber
              }"
            :style="{
                  zIndex: (headFixed && fixedCheckbox) ? 3 : 1
              }"
            v-if="showLineNumber" >
          编号
        </th>
        <th style="text-align: left;padding-left: 5px;" :class="{
                'customize-table-head-sticky': headFixed,
                'customize-table-col-sticky-left': column.fixed == 'left',
                'customize-table-col-sticky-right': column.fixed == 'right'
              }"
            :style="{
                  zIndex: (headFixed && (column.fixed == 'left' || column.fixed == 'right')) ? 3 : 1
              }"
            v-for="column in columns" :key="column.field">{{ column.desc }}</th>
        </thead>
        <tbody>
        <tr  @click.stop="handleTrClick(rowIndex)"  class="customize-table-tr" v-for="(item,rowIndex) in refData" :key="rowIndex" :id="rowIndex">
          <td class="customize-table-checkbox-th"
              :class="{
                  'customize-table-col-sticky-left': fixedCheckbox
              }"
              v-if="showCheckBox">
            <span @click.stop>
              <input :checked="item.checked" @change.stop="handleRowCheckboxChange(rowIndex,$event)" type="checkbox"/>
            </span>
          </td>
          <td class="customize-table-checkbox-th"
              :class="{
                  'customize-table-col-sticky-left': fixedLineNumber
              }"
              v-if="showLineNumber">
            {{ rowIndex + 1 }}
          </td>
          <td v-for="(column, colIndex) in columns" :width="column.width == undefined ? 'auto' : column.width "
            :class="{
              'customize-table-col-sticky-left': column.fixed == 'left',
              'customize-table-col-sticky-right': column.fixed == 'right'
            }"
          >
            <div v-if="!column.isSlot" >
              {{
                handleCellVal(item,column,colIndex,rowIndex)
              }}
            </div>
            <div v-if="column.isSlot"   >
              <slot :name="column.field" :rowData="toRaw(item)" :rowIndex="rowIndex"></slot>
            </div>
          </td>
        </tr>
        </tbody>
      </table>
    </div>
    <div class="customize-table-page" v-if="showPage && !urlIsEmpty  ">
      <div class="customize-table-page-pre"
           :style="{
            'pointer-events': pageRang[0] != 1 ? 'all' : 'none'
          }"
           @click="handlePage('pre')"> &lt;
      </div>
      <div class="customize-table-page-num"
           :class="{
            'customize-table-page-num-focus' : num == activeNum
          }"
           v-for="(num,index) in pageRang " @click="handlePageNum(num)" :index="index" :key="index">{{ num }}
      </div>
      <div class="customize-table-page-next" @click="handlePage('next')"
           :style="{
            'pointer-events': pageRang[pageRang.length - 1] != pageCount ? 'all' : 'none'
          }"
      > &gt;
      </div>
      <div class="customize-table-page-input">
        当前：{{ pageCount == null ? 0  : activeNum }}&nbsp;页，共: {{refData == undefined ? 0 : refData.length}}条 &nbsp;
        共：{{ pageCount == null ? 0 : pageCount }}&nbsp;页，前往:&nbsp;
        <input v-model="inputPageNum" type="number" name="" @keyup.enter="goAppointPage"  id="">
        &nbsp;页
      </div>
    </div>
  </div>
</template>
<script lang="ts" setup>
import {ref, toRaw, toRef, computed, onMounted, inject, onBeforeMount, onUpdated} from 'vue';
import type {TableOptions, TableColumn} from '@/components/plugs/table/TableInterface.ts';
import {AXIOS_NAME, TOKEN_NAME_KEY, TOKEN_VALUE_KEY} from "@/constant/constant.ts";
import {ElMessage} from "element-plus";

const prop = withDefaults(defineProps<TableOptions>(), {
  columns: [] as any,
  url: "",
  data: [] as any,
  handleDic: true,
  params: {},
  showCheckBox: false,
  headFixed: true,
  showPage: true,
  showLineNumber: true,
  fixedCheckbox: true,
  fixedLineNumber: true,
  width: "100%",
  height: "100%",
  onRowCheckedChange: (selected: boolean, rowData: object, rowIndex: number) => {
  },
  onRowClick: ( rowData: object, rowIndex: number) => {
  },
  onRowDblClick: (rowData: object, rowIndex: number) => {
  },
  onAllCheckedChange: (selected: boolean, data: object[]) => {
  },
  loadSuccess: (data: object[]) => {
  }
});
const {onRowCheckedChange, onAllCheckedChange,onRowClick,onRowDblClick, loadSuccess, data, params, url,height} = prop;
const allCheckboxChange = ref(false);
const refData = ref([]);
const $axios = inject(AXIOS_NAME);
const pageCount = ref(0);
const showPagDiv = ref(10);//控制展示多少个页码
const limit = ref(20);
const activeNum = ref(0);
const inputPageNum = ref(null);
const pageRang = ref([]);
const topFixed = ref(1);
const customizeTable = ref(null);
let searchParams:{} = {};
let dicData:{} = {};

const urlIsEmpty = computed(() => {
  return url == '' || url == undefined || url == null
});

onBeforeMount(()=>{
  if(urlIsEmpty){
    refData.value = toRaw(data);
  }
  getAjaxData();
});

let timer:any;

getDicData();

const handleCellVal = (rowData,head,colIndex,rowIndex) =>{
  rowData = toRaw(rowData);
  if(head.colFormatVal != undefined && head.colFormatVal != null){
     return head.colFormatVal(rowData,dicData[head.dicType],colIndex,rowIndex);
  }
  if(head.dicType != null && head.dicType != undefined){
      const dicItemData = dicData[head.dicType];
      for(const item of dicItemData){
        if(item.val == rowData[head.field]){
          return item.text;
        }
      }
  }
  return rowData[head.field];
}

//处理行单击，双击事件
const handleTrClick = (rowIndex:number) =>{
  if(timer != undefined){
    onRowDblClick(toRaw(refData.value[rowIndex]),rowIndex);
    clearTimeout(timer);
    timer = undefined;
    return;
  }
  timer = setTimeout(function (){
    onRowClick(toRaw(refData.value[rowIndex]),rowIndex);
    clearTimeout(timer);
    timer = undefined;
  },400);
}

//出来table 整体checkbox事件
const handleAllChange = (event:events) => {
  const checked = event.target.checked;
  allCheckboxChange.value = checked;
  refData.value.forEach((item:any, index:number) => {
    refData.value[index].checked = checked;
  });
  onAllCheckedChange(checked,toRaw(refData.value));
}

//处理行checkbox change事件
const handleRowCheckboxChange = (rowIndex:number, event:events) => {
  event.stopPropagation();
  event.preventDefault();

  const checked = event.target.checked;
  refData.value[rowIndex].checked = checked;
  onRowCheckedChange(checked,toRaw(refData.value[rowIndex]),rowIndex);
  if (!checked) {
    allCheckboxChange.value = false;
    return;
  }
  let flag = true;
  refData.value.forEach((item:any, index:number) => {
    if (!item.checked) {
      flag = false;
    }
  });
  allCheckboxChange.value = flag;
}

//中间页码div点击事件
const handlePageNum = (pageNum:number) => {
  activeNum.value = pageNum;
  //inputPageNum.value = pageNum;
  getAjaxData({});
}

//处理翻页
const handlePage = (type:string) => {
  if (type == 'next') {
    let startNum:number = pageRang.value[pageRang.value.length - 1];
    let endNum:number = startNum + showPagDiv.value - 1;
    if (endNum > pageCount.value) {
      endNum = pageCount.value;
      startNum = pageCount.value - showPagDiv.value + 1;
    }
    handleShowPageNums(startNum, endNum);
    return;
  }
  let endNum:number = pageRang.value[0];
  let startNum:number = endNum - showPagDiv.value + 1;
  if (startNum < 1) {
    startNum = 1;
    endNum = showPagDiv.value;
  }
  handleShowPageNums(startNum, endNum);
}

function handleShowPageNums(startNum:number, endNum:number) {
  pageRang.value.splice(0, pageRang.value.length);
  if (pageCount.value <= 0) {
    return;
  }
  if (pageCount.value <= showPagDiv.value) {
    startNum = 1;
    endNum = pageCount.value;
  }
  for (let i:number = startNum; i <= endNum; i++) {
    pageRang.value.push(i);
  }
}

//跳转到指定页面
const goAppointPage = (event:events) => {
  if (inputPageNum.value < 1 || inputPageNum.value > pageCount.value) {
    inputPageNum.value = activeNum.value;
    return;
  }
  let startNum = inputPageNum.value;
  let endNum = startNum + showPagDiv.value - 1;
  if (endNum > pageCount.value) {
    endNum = pageCount.value
    startNum = pageCount.value - showPagDiv.value + 1;
  }
  handleShowPageNums(startNum, endNum);
  activeNum.value = inputPageNum.value;
  getAjaxData();
};

onMounted(() => {
  //加载完成回调
 if(urlIsEmpty){
   calculateColsFixed();
   loadSuccess(toRaw(data));
 }
});

onUpdated(() =>{
  calculateColsFixed();
  loadSuccess(toRaw(refData.value));
});


//计算table sticky
function calculateColsFixed(){
  let lThs:any = customizeTable.value.querySelector("thead").querySelectorAll(".customize-table-col-sticky-left");
  let tbody:any = customizeTable.value.querySelector("tbody");
  let leftNum = 0;
  lThs.forEach((item:any,index:number) => {
      item.style.left = leftNum + "px";
      tbody.querySelectorAll("tr").forEach((tr:any) => {
        tr.querySelectorAll(".customize-table-col-sticky-left")[index].style.left = leftNum + "px";
      });
    leftNum += item.offsetWidth;
  });

  let rThs = customizeTable.value.querySelector("thead").querySelectorAll(".customize-table-col-sticky-right");
  let rightNum = 0;
  for(let i = rThs.length - 1 ; i >= 0;i--){
    let item = rThs[i];
    item.style.right = rightNum + "px";
    tbody.querySelectorAll("tr").forEach((tr) => {
      tr.querySelectorAll(".customize-table-col-sticky-right")[i].style.right = rightNum + "px";
    });
    rightNum += item.offsetWidth;
  }
}

//ajax
 async  function getAjaxData(){
    if(!isJsonObject(searchParams)){
        throw new Error("传入参数应该为json格式");
    }
    searchParams.start = activeNum.value;//当前页码
    searchParams.limit = limit.value;//请求数量
   for (const key in  params){
     searchParams[key] = params[key];
   }
    const result = $axios.post(url, searchParams).then(
        respone => {
          const pageData = respone.data;
          refData.value = pageData.data;
          pageCount.value = pageData.pageCount;
          allCheckboxChange.value = false;
          activeNum.value = activeNum.value == 0 ? 1 : activeNum.value;
          if(pageData.pageCount == 0 || pageData == null
              || pageData.pageCount  == null || pageData.pageCount == undefined){
            activeNum.value = 0;
            return;
          }
          let statNum = pageRang.value.length <= 0 ? 1 : pageRang.value[0];
          let endNum = pageRang.value.length <= 0 ? showPagDiv.value : pageRang.value[pageRang.value.length - 1];
          handleShowPageNums(statNum, endNum);
        }).catch(error => {
            ElMessage.error("请求失败：" + error);
        }).finally(() => {
    });
}

async function getDicData(){
 const result = await $axios.post("/dictionary/getGroupMapDic",{});
  const data = result.data;
  dicData = data;
}

function isJsonObject(obj: any): boolean {
  try {
    const jsonString = JSON.stringify(obj);
    const parsedObj = JSON.parse(jsonString);
    return JSON.stringify(parsedObj) === jsonString;
  } catch (error) {
    return false;
  }
}

//子组件暴露方法给父组件
const getAllData = ()=>{
  return toRaw(data);
}

const getCheckedData = ()=>{
  let temp:any[] = [];
  refData.value.forEach((item:any)=>{
    if(item.checked){
      temp.push(toRaw(item));
    }
  });
  return temp;
}

const reload = (params:any) =>{
  activeNum.value = 1;
  searchParams = params == undefined || params == null ? {} : params;
  getAjaxData();
}

defineExpose({getAllData,getCheckedData,reload});

</script>
<style scoped>

.customize-table-container{
  overflow: auto;
  position: relative;
  border: 1px solid #fbfbfb;
}
.customize-table {
  border: 1px solid #fbfbfb;
  border-collapse: collapse;
}

.customize-table-head-sticky{
  position: sticky;
  top: 0;
  z-index: 1;
}

.customize-table-col-sticky-left,.customize-table-col-sticky-right{
  left: 0;
  position: sticky;
  z-index: 1;
}

.customize-table td, th {
  height: 35px;
  box-sizing: border-box;
}

.customize-table th {
  color: #94979D;
  font-size: 14px;
  background-color: #fbfbfb;
}

.customize-table td {
  color: #66686B;
  padding-left: 10px;
  font-size: 14px;
}

.customize-table-checkbox-th {
  width: 50px;
  padding-left: 0px !important;
  text-align: center;
}

.customize-table-page {
  width: calc(100% - 10px);
  height: 35px;
  padding-top: 10px;
  display: flex;
  color: #66686B;
  padding-left: 1px;
}

.customize-table-page-num {
  width: 40px;
  height: 30px;
  font-size: 14px;
  text-align: center;
  line-height: 30px;
  cursor: pointer;
  background-color: #F0F2F5;
  margin-right: 5px;
}

.customize-table-page-num-focus {
  background-color: #409EFF;
  color: white;
}

.customize-table-page-pre, .customize-table-page-next {
  width: 32px;
  height: 32px;
  font-size: 16px;
  text-align: center;
  line-height: 30px;
  cursor: pointer;
  background-color: #F0F2F5;
  margin-right: 5px;
}

.customize-table-page-input {
  font-size: 14px;
  margin-left: 5px;
}

.customize-table-page-input input {
  width: 50px;
  height: 26px;
  border: 1px solid #F0F2F5;
}
.customize-table tr:nth-child(even) > td{
  background-color: #fbfbfb;
}
.customize-table tr:nth-child(odd) > td{
  background-color: white;
}
</style>